(function(document, window, tm, undefined){
	if(!tm || !tm.ch){
		return;
	}
	
	var browser,
    browserVersion,
    language,
    os,
    path,
    params,
    docEl,
	infos				= {}
    user_id				= tm.ch.s,
    isFirstSession		= 1,
    isLive				= false,
    plugins				= [],
    pluginsTransferred	= false,
    referrer			= tm.ch.x,
    resolution			= tm.ch.r,
    htmlUUID			= "",
    ssl					= tm.ch.ssl,
    expiresAt			= 900000,
    expired				= false,
    allFuncs			= [],
	window.tm = tm;

    init = function() {
		
        //Setting the initial values returned by the preload.js
        infos = helpers.getPreloadParams(tm.info);
        if (ssl) {
            transmit.savePath = "https://s.trakk247.com/";
        }
        if (referrer == "null") {
            referrer = "";
        }
        json.reset();
		var browserAndOS = helpers.detectBrowserAndOS(navigator,window);
		browser = browserAndOS.browser;

/*XXXXXX
		function setBrowser
		
		sets shortcode for browsers
		tm.ts.browser.isIE -- IE
		tm.ts.browser.isCH -- Chrome
		tm.ts.browser.isOP -- Opera
		tm.ts.browser.isFF -- Firefox
		tm.ts.browser.isSA -- Safari
		*/
		helpers.setBrowser(browserAndOS);
		
        // tm.ts.os = tm.ts.helpers.getOperatingSystem();
		os = browserAndOS.OS;
        language = helpers.getLanguage();
//XXXXX        // helpers.setPlugins(); stimmt was nicht
        params = helpers.getParams();
        path = helpers.getPath();
        docEl = helpers.getDocElement();
        if (browser != "") {
            
            store.lStorage = window.localStorage;
            store.sStorage = window.sessionStorage || window.localStorage;
            cookies.init();
            if (user_id != null) {
                transmit.lastPageValues();
                if ( !browser.isIE || browserVersion >= 8 ) {
                    html.calculateChecksum();
                    htmlUUID = html.compareChecksum();
					listener.addEvent(window, "load", html.initOverride);
                }
                container.setTrackContainer();
                listener.addEvent(document, "mousemove", store.position);
                listener.addEvent(document, "mousedown", store.setMouseDown);
                listener.addEvent(document, "mouseup", store.setMouseUp);
                listener.addEvent(document, "mousewheel", helpers.setWheelScroll);
                listener.addEvent(window, "scroll", helpers.setBarScroll);

// XXXXXX		SET GLOBAL EVENTS FOR DELEGATION
                listener.addEvent(document, "mouseover", container.delegationEventWeiche);
                listener.addEvent(document, "mouseout", container.delegationEventWeiche);
                listener.addEvent(document, "click", container.delegationEventWeiche);
                listener.addEvent(document, "focus", container.delegationEventWeiche);
                listener.addEvent(document, "change", container.delegationEventWeiche);

// XXXXXX                tm.ts.container.setClickContainers();

// （╯°□°）╯︵ ┻━┻		Eval im interval BÖÖÖÖSE 
                if (isLive) {
                    // setInterval("store.checkExpiration('live')", 5000);
                    // setInterval("transmit.pageValues(json.JSONEvents)", 5000);
                } else {
                    //tm.ts.transmit.sendInterval = setInterval("tm.ts.transmit.pageValues(tm.ts.json.JSONEvents)", 1000);
                }
                transmit.sessionLoad();
                listener.addEvent(window, "unload", transmit.sessionUnload);
            }           
        }
    };

    var encrypt = {
		lzw: {
			compress: function(uncompressed) {
				var dictSize = 256, dictionary = {},
				w = "",
				result = [],
				i,c,wc;

				for (i = 0; i < 256; i++) {
					dictionary[String.fromCharCode(i)] = i;
				}

				for (i = 0; i < uncompressed.length; i++) {
					c = uncompressed.charAt(i);
					wc = w + c;
					if (dictionary[wc]) {
						w = wc;
					} else {
						result.length > 0 && result.push(",");
						result.push(dictionary[w]);

						dictionary[wc] = dictSize++;
						w = "" + c;
					}
				}
				// Output the code for w.
				if (w != "") {
					result.length > 0 && result.push(",");
					result.push(dictionary[w]);
				}
				return result.join("");
			},
            decompress: function(compressedString) {
                var compressed = compressedString.split(","), 
				dictSize = 256, dictionary = [],
				i,k,
				w = String.fromCharCode(compressed[0]),
				result = [w]
				entry = "";

                for (i = 0; i < 256; i++) {
                    dictionary[i] = String.fromCharCode(i);
                }

                for (i = 1; i < compressed.length; i++) {
                    k = compressed[i];
                    if (dictionary[k]) {
                        entry = dictionary[k];
                    } else if (k == dictSize) {
                        entry = w + w.charAt(0);
                    } else {
                        return null;
                    }

                    result.push(entry);

                    dictionary[dictSize++] = w + entry.charAt(0);
                    w = entry;
					entry = "";
                }
                return result.join("");
            }
        },
        base64: {
            keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
            encode: function(input) {
				var output = [],chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0, b64Short = encrypt.base64;
				input = b64Short.utf8Encode(input);
				while (i < input.length) {
                    chr1 = input.charCodeAt(i++);
                    chr2 = input.charCodeAt(i++);
                    chr3 = input.charCodeAt(i++);
                    enc1 = chr1 >> 2;
                    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                    enc4 = chr3 & 63;
                    if (isNaN(chr2)) {
                        enc3 = enc4 = 64;
                    } else if (isNaN(chr3)) {
                        enc4 = 64;
                    }
                    output.push(b64Short.keyStr.charAt(enc1), b64Short.keyStr.charAt(enc2), b64Short.keyStr.charAt(enc3), b64Short.keyStr.charAt(enc4));
				}
				return output.join("");
            },
			decode: function(input) {
				var output = [],chr1, chr2, chr3,enc1, enc2, enc3, enc4,i = 0,b64Short = encrypt.base64;
				input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
				while (i < input.length) {
					enc1 = b64Short.keyStr.indexOf(input.charAt(i++));
					enc2 = b64Short.keyStr.indexOf(input.charAt(i++));
					enc3 = b64Short.keyStr.indexOf(input.charAt(i++));
					enc4 = b64Short.keyStr.indexOf(input.charAt(i++));
					chr1 = (enc1 << 2) | (enc2 >> 4);
					chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
					chr3 = ((enc3 & 3) << 6) | enc4;
					output.push(String.fromCharCode(chr1));
					if (enc3 != 64) {
						output.push(String.fromCharCode(chr2));
					}
					if (enc4 != 64) {
						output.push(String.fromCharCode(chr3));
					}
				}
				return b64Short.utf8Decode(output.join(""));
			},
			utf8Encode: function(string) {
				var utftext = [],n,c;
				string = string.toString().replace(/\r\n/g,"\n");

				for (n = 0; n < string.length; n++) {
					c = string.charCodeAt(n);
					if (c < 128) {
						utftext.push(String.fromCharCode(c));
					} else if ((c > 127) && (c < 2048)) {
						utftext.push(String.fromCharCode((c >> 6) | 192));
						utftext.push(String.fromCharCode((c & 63) | 128));
					} else {
						utftext.push(String.fromCharCode((c >> 12) | 224));
						utftext.push(String.fromCharCode(((c >> 6) & 63) | 128));
						utftext.push(String.fromCharCode((c & 63) | 128));
					}
				}
				return utftext.join("");
			},
			utf8Decode: function(utftext) {
				var string = [];
				var i = 0;
				var c = c1 = c2 = 0;
				while (i < utftext.length) {
					c = utftext.charCodeAt(i);
					if (c < 128) {
						string.push(String.fromCharCode(c));
						i++;
					} else if ((c > 191) && (c < 224)) {
						c2 = utftext.charCodeAt(i+1);
                        string.push(String.fromCharCode(((c & 31) << 6) | (c2 & 63)));
						i += 2;
					} else {
						c2 = utftext.charCodeAt(i+1);
						c3 = utftext.charCodeAt(i+2);
                        string.push(String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)));
						i += 3;
					}
				}
				return string.join("");
            }
        }
    };

    var json = {
        JSONSessionLoad: {},
        JSONEvents: {},
        JSONCookie: {e:[]},
        reset: function() {
            json.JSONEvents = {e:[]};
        },
        toString: function(jsonObj) {
			if(JSON){
				return JSON.stringify(jsonObj);
			}
            var JSONString = '{';
            for (var key in jsonObj) {
                if (typeof(jsonObj[key]) == 'object') {
                    JSONString += '"'+ key + '":[';
                    var jsonSubObj = jsonObj[key];
                    for (var subKey in jsonSubObj) {
                        if (typeof(jsonSubObj[subKey]) != "function" && typeof(jsonSubObj[subKey]) != "object") {
                            JSONString += '"'+ jsonSubObj[subKey] + '",';
                        }
                    }
                    JSONString = JSONString.substring(0, JSONString.length - 1);
                    JSONString += '],';
                } else {
                    JSONString += '"'+ key + '":"' + jsonObj[key] + '",';
                }
            }
            JSONString = JSONString.substring(0, JSONString.length - 1);
            JSONString += '}';
            return JSONString;
        }
    };

	var helpers = {
        maxUrlLength: 10000,
        maxDynamicUrlLength: 100000,
        maxSendLength: 100000,
        lastScrolLEvent: null,
        clientSize:{},
		headTag: document.getElementsByTagName("HEAD")[0],
//XXXXX each geliehen von underscore.js
// each_.each(list, iterator, [context])
// Iterates over a list of elements, yielding each in turn to an iterator function. 
// The iterator is bound to the context object, if one is passed. 
// Each invocation of iterator is called with three arguments: (element, index, list). 
// If list is a JavaScript object, iterator's arguments will be (value, key, list). 
// Delegates to the native forEach function if it exists.
		each: function(obj, iterator, context) {
			var nativeForEach = !!Array.prototype.forEach, breaker = {};
			if (obj == null) return;
			if (nativeForEach && obj.forEach === nativeForEach) {
				obj.forEach(iterator, context);
			} else if (obj.length === +obj.length) {
				for (var i = 0, l = obj.length; i < l; i++) {
					if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return;
				}
			} else {
				for (var key in obj) {
					if (hasOwnProperty.call(obj, key)) {
						if (iterator.call(context, obj[key], key, obj) === breaker) return;
					}
				}
			}
		},
//XXXXXX find geliehen von underscore.js
// Looks through each value in the list, returning the first one that passes a truth test (iterator).
// The function returns as soon as it finds an acceptable element, and doesn't traverse the entire list.
		find: function(obj, iterator, context) {
			var result;
			helpers.any(obj, function(value, index, list) {
				if (iterator.call(context, value, index, list)) {
					result = value;
					return true;
				}
			});
			return result;
		},
//XXXXXX any geliehen von underscore.js
// Returns true if any of the values in the list pass the iterator truth test. 
// Short-circuits and stops traversing the list if a true element is found. 
// Delegates to the native method some, if present.
		any: function(obj, iterator, context) {
			var nativeSome = Array.prototype.some;
			var breaker = {};			
		    iterator = iterator || function(value){return value};
			var result = false;
			if (obj == null) return result;
			if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
			helpers.each(obj, function(value, index, list) {
				if (result |= iterator.call(context, value, index, list)) return breaker;
			});
			return !!result;
		},
//XXXXXX angelehnt an underscore.js, gibt index von item in array zurück, sorted möglichkeit entfernt
		indexOf: function(array, item) {
			if (array == null) return -1;
			var i, l, nativeIndexOf = Array.prototype.indexOf;
			if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
			for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
			return -1;
		},
		addToHead: function(elem){
			!!elem && helpers.headTag.appendChild(elem);
		},
        getPreloadParams: function(params) {
            var infoParams = encrypt.lzw.decompress(encrypt.base64.decode(params));
            var infoArr = infoParams.split("&");
            var infoKeyValArr = new Object();
            for (var i = 0; i < infoArr.length; i++) {
                var keyValueArr = infoArr[i].split("=");
                if (keyValueArr[0] == "live") {
                    if (keyValueArr[1] != "") {
                        isLive = true;
                    }
                }
                infoKeyValArr[keyValueArr[0]] = keyValueArr[1];
            }
            return infoKeyValArr;
        },
		//NEEDS NAVIGATOR AND WINDOW ALS ATTRIBUTES
		detectBrowserAndOS : function(n,w){

			var versionSearchString,
			np = n.platform,
			nua = n.userAgent,
			nv = navigator.vendor,
			wo = w.opera,
			ch = "Chrome",
			ow1 = "OmniWeb",
			ver = "Version",
			ic = "iCab",
			ff = "Firefox",
			ca = "Camino",
			net = "Netscape",
			moz = "Mozilla",
			dataBrowser = [ {s: nua, sS: ch, i: ch }, 
							{ s: nua, sS: ow1, vS: ow1+"/", i: ow1 }, 
							{ s: nv, sS: "Apple", i: "Safari", vS: ver }, 
							{ p: wo, i: "Opera", vS: ver },
							{ s: nv, sS: ic, i: ic },
							{ s: nv, sS: "KDE", i: "Konqueror" }, 
							{ s: nua, sS: ff, i: ff }, 
							{ s: nv, sS: ca, i: ca }, 
							{ s: nua, sS: net, i: net }, 
							{ s: nua, sS: "MSIE", i: "Explorer", vS: "MSIE" },
							{ s: nua, sS: "Gecko", i: moz, vS: "rv" }, 
							{ s: nua, sS: moz, i: net, vS: moz } 
			],
			dataOS = [	{ s: np, sS: "Win", i: "Windows"}, 
						{ s: nua, sS: "Mac", i: "Mac" }, 
						{ s: nua, sS: "iPhone", i: "iPhone/iPod" }, 
						{ s: np, sS: "Linux", i: "Linux" } 
			],
			bao = {
				browser : (searchString(dataBrowser) || "An unknown browser"),
				version : (searchVersion(n.userAgent) || searchVersion(n.appVersion) || "an unknown version"),
				OS : (searchString(dataOS) || "an unknown OS")
			};
			return bao;

			function searchString(data) {
				for (var i=0;i<data.length;i++)	{
					var dataString = data[i].s;
					var dataProp = data[i].p;
					versionSearchString = data[i].vS || data[i].i;
					if (dataString) {
						if (dataString.indexOf(data[i].sS) != -1)
							return data[i].i;
					}
					else if (dataProp)
						return data[i].i;
				}
			};

			function searchVersion(dataString) {
				var index = dataString.indexOf(versionSearchString);
				if (index == -1) return;
				return parseFloat(dataString.substring(index+versionSearchString.length+1));
			};

		},
// XXXXXX  SET booleans for browsers
		setBrowser: function(bType){
			browser.isIE = bType == "Explorer";
			browser.isCH = bType == "Chrome";
			browser.isOP = bType == "Opera";
			browser.isFF = bType == "Firefox";
			browser.isSA = bType == "Safari";
		},
        getPath: function() {
			return window.location.pathname;
        },
        getParams: function() {
            return window.location.search;
        },
        getDocElement: function() {
             return (typeof(document.compatMode) != "undefined" && document.compatMode != "BackCompat") ? "documentElement" : "body";
        },
        setPlugins: function() {
            if (!browser.isIE) {
                var plugins = navigator.plugins;
                for (var i = 0; i < plugins.length; i++) {
                    var plugin = null;
                    if (plugins[i].description.search(/Flash/) != -1) {
                        plugin = "flash";
                    } else if (plugins[i].description.search(/Adobe PDF/) != -1) {
                        plugin = "pdf";
                    } else if (plugins[i].description.search(/Java Plug-in/) != -1) {
                        plugin = "java";
                    } else if (plugins[i].name.search(/Silverlight/) != -1) {
                        plugin = "silverlight";
                    }
                    if (plugin != null) {
                        var version = "";
                        if (plugin == "java") {
                            version = plugins[i].description.split(".")[1];
                         } else if (plugin == "silverlight") {
                            version = plugins[i].description.split(".")[0];
                         } else {
                            version = plugins[i].description.split(".")[0];
                        }
                        for (var j = (version.length - 1); j >= 0; j--) {
                            var numTest = /\d/;
                            if (!numTest.test(version.charAt(j))) {
                                break;
                            }
                        }
                        if (helpers.trim(version.substr(j + 1)) != "" && version != null && version !== undefined) {
                            plugin += "|" + version.substr(j + 1);
                        } else {
                            plugin += "|0";
                        }
                        plugins.push(plugin);
                    }
                }
                if (browser.isFF) {
                    var firebug1Image = helpers.getTrackingImage("tm_plugins");
                    listener.addEvent(firebug1Image, "load", function(e){helpers.removeImageTag(e);plugins.push("firebug|0")});
                    listener.addEvent(firebug1Image, "error", function(e){helpers.removeImageTag(e);});
                    firebug1Image.setAttribute("src", "chrome://firebug/content/firebug.png");
                    var firebug2Image = helpers.getTrackingImage("tm_plugins");
                    listener.addEvent(firebug2Image, "load", function(e){helpers.removeImageTag(e);plugins.push("firebug|0")});
                    listener.addEvent(firebug2Image, "error", function(e){helpers.removeImageTag(e);});
                    firebug2Image.setAttribute("src", "chrome://firebug/content/firebug32.png");
                    var webDevImage = helpers.getTrackingImage("tm_plugins");
                    listener.addEvent(webDevImage, "load", function(e){helpers.removeImageTag(e);plugins.push("web_dev_toolbar|0")});
                    listener.addEvent(webDevImage, "error", function(e){helpers.removeImageTag(e);});
                    webDevImage.setAttribute("src", "chrome://webdeveloper/content/images/logo/large.png");
                }
            } else {
                var control = null;
                try {
                    control = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
                } catch (e) {}
                if (control) {
                    var version = control.GetVariable('$version').substring(4).split(',')[0];
                    if (helpers.trim(version) != "" && version != null && version !== undefined) {
                        plugins.push("flash|" + version);
                    } else {
                        plugins.push("flash|0");
                    }
                }
                control = null;
                try {
                    control = new ActiveXObject('AcroPDF.PDF');
                } catch (e) {}
                if (!control) {
                    try {
                        control = new ActiveXObject('PDF.PdfCtrl');
                    }catch (e) {}
                }
                if (control) {
                    var version = control.GetVersions().split(",")[0].split("=")[1].split(".")[0];
                    if (helpers.trim(version) != "" && version != null && version !== undefined) {
                        plugins.push("pdf|" + version);
                    } else {
                        plugins.push("pdf|0");
                    }
                }
                if (navigator.javaEnabled()) {
                    plugins.push("java|0");
                }
                /*if (document.googleBar && typeof(document.googleBar.Search) != "undefined") {

                }*/
            }
        },
        trim: function(str) {
            return (typeof(str) == "string") ? str.replace(/^\s+|\s+$/g,""): str;
        },
		fixedGMTString: function(date) {
			var startDate = new Date(1970,0,1,12), isBug = startDate.toGMTString().indexOf("02") > 0;
			helpers.fixedGMTString = function(date){
				isBug && date.setTime(date.getTime() - 1000 * 60 * 60 * 24);
		   		return date.toGMTString();
			}
			return helpers.fixedGMTString(date);
		},
		getTrackingImage: function(cssClass) {
			var tmImage = document.createElement("img");
			tmImage.className = cssClass;
			helpers.addToHead(tmImage);
			return tmImage;
		},
		removeImageTag: function(e) {
			var element = e.srcElement || e.target;
			element.parentNode.removeChild(element);
		},
        nodeListToArray: function(nodeList) {
            var arr = [],i;
            for (i = 0; i < nodeList.length; i++) {
                nodeList.item(i).nodeType == 1 && arr.push(nodeList.item(i));
            }
            return arr;
        },
        getElapsedTime: function(oldTime) {
            return (new Date().getTime() - oldTime);
        },
		getPosition: function(e) {
			var currentPosition = {},xPos,yPos;
						
			if (browser.isIE) {
				xPos = e.clientX - container.trackContainer.offsetLeft + document[docEl].scrollLeft;
				yPos = e.clientY + document[docEl].scrollTop;
			} else {
				xPos = e.pageX - container.trackContainer.offsetLeft;
				yPos = e.pageY;
			}
			currentPosition.xPos = Math.round(xPos);
			currentPosition.yPos = Math.round(yPos);
			
			return currentPosition;
		},
		getBarValue: function() {
			return browser.isIE ? document[docEl].scrollTop : window.pageYOffset;
		},
        setWheelScroll: function(e) {
            store.isWheelScroll = true;
        },
        setBarScroll: function(e) {
            if (!store.isWheelScroll && store.lastEvent != "w") {
                store.isBarScroll = true;
            }
        },
        setClientSize: function() {
            var visibleWidth;
            var visibleHeight;
            if (browser.isIE) {
                visibleWidth = document[docEl].clientWidth;
                visibleHeight = document[docEl].clientHeight;
            } else {
                visibleWidth = window.innerWidth;
                visibleHeight = window.innerHeight;
            }
            helpers.clientSize.visibleWidth = visibleWidth;
            helpers.clientSize.visibleHeight = visibleHeight;
        },
        getScrollBarXPos: function () {
            var test;
            if (browser.isIE) {
                test = (document[docEl].clientWidth - container.trackContainer.offsetLeft - document[docEl].scrollLeft);
            } else {
                test = (window.innerWidth - container.trackContainer.offsetLeft);
            }
            return test;
        },
        getScrollMax: function() {
            var scrollMaxWidth;
            var scrollMaxHeight;
            if (browser.isFF) {
                scrollMaxWidth = window.scrollMaxX;
                scrollMaxHeight = window.scrollMaxY;
            } else {
                scrollMaxWidth = (document[docEl].scrollWidth - document[docEl].scrollHeight);
                scrollMaxHeight = (document[docEl].scrollHeight - document[docEl].clientHeight);
            }
            var scrollMax = {};
            scrollMax.scrollMaxWidth = scrollMaxWidth;
            scrollMax.scrollMaxHeight = scrollMaxHeight;
            return scrollMax;
        },
        getServicePack: function() {
			var sp = navigator.appMinorVersion && navigator.appMinorVersion.match(/SP\d{1}/);
            return sp && sp[0] || "";
        },
        getPluginsAsString: function() {
            var pluginString = "";
            for (var i = 0; i < plugins.length; i++) {
                if (pluginString == "") {
                    pluginString = plugins[i];
                } else {
                    pluginString += "," + plugins[i];
                }
            }
            return pluginString;
        },
        getLanguage: function() {
            var lang = navigator.language || navigator.browserLanguage;
            return lang && lang.split("-")[0];
        },
        getElementsByClass: function(cssClass) {
			if(document.getElementsByClassName){
				return document.getElementsByClassName(cssClass);
			}
            var classesArr = [];
            var myclass = new RegExp('\\b'+cssClass+'\\b');
            var elem = document.getElementsByTagName('*');
            for (var i=0; i<elem.length; i++) {
                var classes = elem[i].className;
                if (myclass.test(classes)) {
                    classesArr.push(elem[i]);
                }
            }
            return classesArr;
        },
        checkLiveFeed: function(e) {
            var element;
            if (browser.isIE) {
                element = e.srcElement;
            }else {
                element = e.currentTarget;
            }
            if (element.height == 2) {
                transmit.liveFeed = true;
            } else {
                transmit.liveFeed = false;
            }
        },
        getAttributes: function(element) {
            var nodes=[];
            var values=[];
            var allowedAttr = ["style", "name", "class", "id", "checked", "disabled", "width", "height", "selected", "type"];
            var attrArr = element.attributes;
            if (attrArr != null) {
                for (var i = 0; i < attrArr.length; i++){
                    var attr = attrArr.item(i);
                    for (var j = 0; j < allowedAttr.length; j++) {
                        if (attr.nodeName == allowedAttr[j]) {
                            nodes.push(attr.nodeName);
                            values.push(attr.nodeValue);
                            break;
                        }
                    }
                }
            }
            return [nodes, values];
        },
        checkMaps: function(element) {
            var linksParent = element;
            while (linksParent != null) {
                if (linksParent.handleTouch === undefined) {
                    linksParent = linksParent.parentNode;
                } else {
                    return true;
                }
            }
            return false;
        },
        rgbToHex: function(rgb) {
            var hex="";
            rgb = rgb.split(",");
            for(var i=0; i<3; i++) {
                var hexArray = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
                var code1 = Math.floor(rgb[i] / 16);
                var code2 = rgb[i] - code1 * 16;
                hex += hexArray[code1];
                hex += hexArray[code2];
            }
            return hex;
        },
        endsWith: function(str, suffix) {
            return str.match(suffix + "$") == suffix;
        },
        getParentInfos: function(element) {
            var parents = [];
            var parent = element;
            var i = 0;
            while (parent !== undefined && parent.tagName !== undefined) {
                parents[i] = {
                    node:parent.tagName.toLowerCase(),
                    // TODO: More than one cssclass for an element
                    cssclass:parent.className,
                    id:parent.id
                };
                parent = parent.parentNode;
                i++;
            }
            return parents;
        }
    };

    var cookies = {
        sessioncookie: "",
        seessioncookieref: "",
        expiresDate: new Date(new Date().getTime() + 1000*60*60*24),
        init: function() {
            cookies.sessioncookie = "trk_mouse_" + tm.id;
            if (user_id == "") {
                user_id = cookies.getCookie(cookies.sessioncookie);
            }
            if (user_id == null) {
                cookies.setCookie(cookies.sessioncookie, infos.user_id, cookies.expiresDate, "/");
                user_id = cookies.getCookie(cookies.sessioncookie);
            } else {
                isFirstSession = 0;
            }
            store.superUserCookie();
            cookies.sessioncookieref = "trk_mouse_" + tm.id + "_x";
            if (tm.ch.f == 1) {
                cookies.setCookie(cookies.sessioncookieref, referrer, new Date(new Date().getTime() + 1000*60*15), "/");
            }
        },
        getCookie: function(name) {
			var pattern = name+"=[^;]*",
			match = document.cookie.match(pattern);
            return match && match[0];
        },
        setCookie: function(name, value, expires, path, domain, secure) {
            var newCookie = [name, "=", escape(value)];
			!!expires	&&	newCookie.push("; expires=", helpers.fixedGMTString(expires));
            !!path 		&&	newCookie.push("; path=", path);
			!!domain	&&	newCookie.push("; domain=", domain);
			!!secure	&&	newCookie.push("; secure");
            document.cookie = newCookie.join("");
		}
    };

    var transmit = {
        savePath: "http://192.168.1.22/~tim/trakkmouse/",
        // savePath: "http://s.trakk247.com/",
        saveHtml: "saveHTML_local.php",
        // saveHtml: "sh/",
        saveLastFile: "saveLastFlatfile_local.php",
        // saveLastFile: "slf/",
        saveFile: "saveFlatfiles_local.php",
        // saveFile: "sf/",
        saveError: "saveError_local.php",
        // saveError: "se/",
        loadDataSent: false,
        liveFeed: false,
        sendInterval: null,
        lastPageValues: function() {
            if (store.sStorage) {
                var JSONString = "";
                if (store.sStorage.getItem(user_id) != null) {
                    var timestamps = store.sStorage.getItem(user_id).toString().split("|");
                    for (var i = 0; i < timestamps.length; i++) {
                        if (store.sStorage.getItem(timestamps[i]) != null) {
                            var lastModified = store.sStorage.getItem(timestamps[i] + "_lm");
                            if (lastModified != null) {
                                if ((new Date().getTime() - lastModified) < expiresAt) {
                                    JSONString = store.sStorage.getItem(timestamps[i]).toString().replace(/\\/g, "");
                                    if (JSONString != "") {
                                        var params = 't=' + new Date().getTime() + '&timestamp=' + timestamps[i] + '&user_id=' + user_id + '&json=' + JSONString;
                                        params = encrypt.base64.encode(encrypt.lzw.compress(params));
                                        if (params.length > helpers.maxSendLength) {
                                            transmit.valuesSplitted(params, 0, parseInt(Math.random() * 1000), "slf", transmit.saveLastFile);
                                        } else {
                                            var request = transmit.savePath + transmit.saveLastFile + "?" + params;
                                            var tmImage = helpers.getTrackingImage("");
                                            listener.addEvent(tmImage, "load", helpers.removeImageTag);
                                            tmImage.setAttribute("src", request);
                                        }
                                    }


                                }
                                store.sStorage.removeItem(timestamps[i] + "_lm");
                            }
                            store.sStorage.removeItem(timestamps[i]);
                        }
                    }
                    store.sStorage.removeItem(user_id);
                }
            }
        },
        page: function() {
            if (html.loops < html.pageArr.length) {
                var params = 't=' + new Date().getTime() + '&timestamp=' + tm.st + '&user_id=' + user_id + '&html=' + html.pageArr[html.loops];
                params = encrypt.lzw.compress(params);
                var request = transmit.savePath + transmit.saveHtml + "?" + params;
                html.loops++;
                var tmImage = helpers.getTrackingImage("");
                listener.addEvent(tmImage, "load", transmit.removeImageTransPage);
                tmImage.setAttribute("src", request);
            } else {
                html.initOverride();
            }
        },
		removeImageTransPage: function(e){
			helpers.removeImageTag(e);
			transmit.page();	
		},
        pageValues: function(jsonObj) {
            if ((jsonObj.e == undefined || (jsonObj.e != undefined && jsonObj.e.length > 0) || isLive) && !expired) {
                if (jsonObj.e != undefined && jsonObj.e.length > 3 && !isLive) {
                    //clearInterval(transmit.sendInterval);
                    //transmit.sendInterval = setInterval("transmit.pageValues(json.JSONEvents)", 10000);
                }
                var JSONString = json.toString(jsonObj);
                JSONString = JSONString.replace(/\\/g, "");
                var pluginString = "";
                if (!pluginsTransferred && browser.isFF && helpers.getElementsByClass("tm_plugins").length == 0 && transmit.loadDataSent) {
                   pluginString = helpers.getPluginsAsString();
                   store.superCookie("plugins:" + pluginString, false);
                   pluginsTransferred = true;
                }
                var params = 'live=' + infos.live + '&t=' + new Date().getTime()  + '&timestamp=' + tm.st + '&loadtime=' + helpers.getElapsedTime(tm.st) + '&trk_id=' + tm.id + '&user_id=' + user_id + '&json=' + JSONString + '&plugins=' + pluginString + '&livefeed=' + transmit.liveFeed;
                params = encrypt.base64.encode(encrypt.lzw.compress(params));
                if (params.length > helpers.maxSendLength) {
                    transmit.valuesSplitted(params, 0, parseInt(Math.random() * 1000), "sf", transmit.saveFile);
                } else {
                    var request = transmit.savePath + transmit.saveFile + "?" + params;
                    var tmImage = helpers.getTrackingImage("");
                    if (isLive) {
                        listener.addEvent(tmImage, "load", function(e,helpers){helpers.checkLiveFeed(e);helpers.removeImageTag(e);});
                    } else {
                        listener.addEvent(tmImage, "load", helpers.removeImageTag);
                    }
                    tmImage.setAttribute("src", request);
                }
                json.reset();
                store.lastEvent = null;
            }
            return true;
        },
        valuesSplitted: function(params, partNumber, rndNumber, identifier, file) {
            var parts = Math.ceil(params.length / helpers.maxSendLength);
            var partLength = (params.length / parts);
            if (partNumber < parts) {
                var eParam = "";
                var request = "";
                if ((partNumber + 1) == parts) {
                    eParam = "r=" + identifier + rndNumber + "&u=" + user_id + "&e=0&";
                    request = transmit.savePath + file + "?" + eParam + encodeURIComponent(params.substr((partLength * partNumber)));
                } else {
                    eParam = "r=" + identifier + rndNumber + "&u=" + user_id + "&e=" + (partNumber + 1) + "&";
                    request = transmit.savePath + file + "?" + eParam + encodeURIComponent(params.substr((partLength * partNumber), partLength));
                }
                var tmImage = helpers.getTrackingImage("");
                if (isLive && identifier == "sf") {
                    listener.addEvent(tmImage, "load", function(e,transmit,helpers){transmit.valuesSplitted(params, (partNumber + 1), rndNumber, identifier, file);helpers.checkLiveFeed(e);helpers.removeImageTag(e);});
                    //listener.addEvent(tmImage, "load", function(e){setTimeout('transmit.valuesSplitted(' + params + ', ' + (partNumber + 1) + ', ' + rndNumber + ', ' + identifier + ', ' + file + ')', 500);helpers.checkLiveFeed(e);helpers.removeImageTag(e);});
                } else {
                    listener.addEvent(tmImage, "load", function(e,transmit,helpers){transmit.valuesSplitted(params, (partNumber + 1), rndNumber, identifier, file);helpers.removeImageTag(e);});
                    //listener.addEvent(tmImage, "load", function(e){setTimeout('transmit.valuesSplitted(' + params + ', ' + (partNumber + 1) + ', ' + rndNumber + ', ' + identifier + ', ' + file + ')', 500);helpers.removeImageTag(e);});
                }
                tmImage.setAttribute("src", request);
            }
        },
        sessionLoad: function() {
            // loadDataSent is a workaround for the odd behavior of sending the sessionLoad data twice
            if (!transmit.loadDataSent) {
                transmit.loadDataSent = true;
                var time = helpers.getElapsedTime(tm.st);
                var urlPath = decodeURIComponent(path);
                var params = decodeURIComponent(params);
                urlPath = encodeURIComponent(urlPath + params);
                var referrer = decodeURIComponent(referrer);
                referrer = encodeURIComponent(referrer);
                var pluginString = "";
// XXXXX                if (browser.search(/Firefox/) == -1) {
                if (!browser.isFF) {
                    pluginString = helpers.getPluginsAsString();
                    pluginsTransferred = true;
                    json.JSONSessionLoad = {'trk_id':tm.id, 'host':window.location.host, 'campaign_ids':infos.cp_ids, 'path':urlPath, 'isfirstsession':isFirstSession, 'browser':browser, 'browserversion':browserVersion, 'loadtime':time, 'resolution':resolution, 'os':os, 'country':encodeURI(infos.country), 'region':encodeURI(infos.region), 'city':encodeURI(infos.city), 'language':language, 'plugins':pluginString, 'params':encodeURI(infos.params), 'referrer':referrer, 'html':htmlUUID, 'checksum':html.checksum};
                } else {
                    json.JSONSessionLoad = {'trk_id':tm.id, 'host':window.location.host, 'campaign_ids':infos.cp_ids, 'path':urlPath, 'isfirstsession':isFirstSession, 'browser':browser, 'browserversion':browserVersion, 'loadtime':time, 'resolution':resolution, 'os':os, 'country':encodeURI(infos.country), 'region':encodeURI(infos.region), 'city':encodeURI(infos.city), 'language':language, 'params':encodeURI(infos.params), 'referrer':referrer, 'html':htmlUUID, 'checksum':html.checksum};
                }
                json.JSONSessionLoad.e = [];
                helpers.setClientSize();
                json.JSONSessionLoad.e[0] = 'i::' + helpers.clientSize.visibleWidth + '|' + helpers.clientSize.visibleHeight + '|0|client';
                var scrollMax = helpers.getScrollMax();
                json.JSONSessionLoad.e[1] = 'o::' + scrollMax.scrollMaxWidth + '|' + scrollMax.scrollMaxHeight + '|0|scrollmax';
                var srollBarXPos = helpers.getScrollBarXPos() - 30;
                json.JSONSessionLoad.e[2] = 's::' + srollBarXPos + '|0|0|0';
                store.superCookie(json.JSONSessionLoad, false);
// XXXXXXX                if (browser.search(/Firefox/) == -1) {
                if (!browser.isFF) {
                    store.superCookie("plugins:" + pluginString, false);
                }
                transmit.pageValues(json.JSONSessionLoad);
            }
        },
        sessionUnload: function() {
            if (!expired) {
                var time = helpers.getElapsedTime(tm.st);
                json.JSONEvents.e[json.JSONEvents.e.length] = 'sessiontime::' + time;
                store.superCookie(json.JSONEvents.e[json.JSONEvents.e.length -1], false);
                transmit.pageValues(json.JSONEvents);
            }
        },
        errorCode: function(exception) {
            var urlPath = decodeURIComponent(path);
            urlPath = encodeURIComponent(urlPath);
            var error = user_id + "\t" + errors.funcName + "\t" + encodeURIComponent(exception.message) + "\t" + exception.name + "\t" + exception.code + "\t" + browser + "\t" + browserVersion + "\t" + encodeURIComponent(path);
            var params = 'trk_id=' + tm.id + '&error=' + error;
            params = encrypt.base64.encode(encrypt.lzw.compress(params));
            var request = transmit.savePath + transmit.saveError + "?" + params;
            if (document.images) {
                new Image().src = request;
            }
        }
    };

    var html =  {
        pageArr: [],
        loops: 0,
        checksum: "",
        lastDOMEle: null,
        lastDOMHtml: null,
        setPageArray: function() {
            var html = html.getDoctype();
            html += '<html><head><base href="http://' + window.location.host + path + '" />' + document.getElementsByTagName("HEAD")[0].innerHTML + '</head>';
            html += '<body>' + document.getElementsByTagName("BODY")[0].innerHTML + '</body></html>';
            html = html.inputReplace(html);
            html = encodeURIComponent(html);
            for (var i = 0; html.length > 0; i++) {
                var htmlSlice = html.substr(0, helpers.maxDynamicUrlLength);
                var htmlSliceEndPos = htmlSlice.lastIndexOf("%");
                if (htmlSliceEndPos != -1 && htmlSlice.length == helpers.maxDynamicUrlLength) {
                    htmlSlice = htmlSlice.substr(0, htmlSliceEndPos);
                }
                html.pageArr[i] = htmlSlice;
                if (htmlSlice.length < helpers.maxDynamicUrlLength) {
                    break;
                }
                html = html.substr(htmlSliceEndPos, html.length);
            }
        },
		getDoctype: function() {
			var publicId = "";
			var doctype = "";
			
			
			if (browser.isIE) {
				publicId = window.document.body.parentNode.parentNode.firstChild.text;
				if (publicId != undefined) {
					doctype = publicId;
				}
			} else if (window.document.doctype != null) {
				publicId = window.document.doctype.publicId;
				var systemId = "";
				systemId = window.document.doctype.systemId;
				doctype = '<!DOCTYPE html PUBLIC "' + publicId + '"';
				if (systemId != "") {
					doctype += ' "' + systemId + '"';
				}
				doctype += '>';
			}
			return doctype;
		},
        inputReplace: function(html) {
            var inputs = document.getElementsByTagName("INPUT");
            var inputVals = new Array();
            for (var i = 0; i < inputs.length; i++) {
                inputVals[i] = inputs[i].value;
            }
            var startHtml = html;
            html = "";
            var inpPos = startHtml.toLowerCase().lastIndexOf("input");
            while (inpPos != -1) {
                var subHtml = startHtml.substr(inpPos, startHtml.length - 1);
                for (var i = 0; i < inputs.length; i++) {
                    // Searches for the input value inside the substring, but escapes all regexp characters before
                    if (subHtml.search(inputVals[i].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"))) {
                        var repText = "";
                        for (var j = 0; j < inputVals[i].length; j++) {
                            repText += "&bull;";
                        }
                        subHtml = subHtml.replace(inputVals[i], repText);
                    }
                }
                startHtml = startHtml.substr(0, inpPos);
                inpPos = startHtml.toLowerCase().lastIndexOf("input");
                html = subHtml + html;
            }
            html = startHtml + html;
            return html;
        },
        calculateChecksum: function() {
            var allEleLength = document.body.getElementsByTagName("*").length;
            var imgEle = document.body.getElementsByTagName("IMG");
            var imgEleLength = imgEle.length;
            var imgSrcLength = 0;
            for (var i = 0; i < imgEleLength; i++) {
                imgSrcLength += imgEle[i].src.split("?")[0].length;
            }
            var linkEle = document.body.getElementsByTagName("A");
            var linkEleLength = linkEle.length;
            var linkHrefLength = 0;
            for (var i = 0; i < linkEleLength; i++) {
                linkHrefLength += linkEle[i].href.split("?")[0].length;
            }
            var h1Ele = document.body.getElementsByTagName("H1");
            var h1TextLength = 0;
            for (var i = 0; i < h1Ele.length; i++) {
                h1TextLength += h1Ele[i].innerHTML.length;
            }
            var h2Ele = document.body.getElementsByTagName("H2");
            var h2TextLength = 0;
            for (var i = 0; i < h2Ele.length; i++) {
                h2TextLength += h2Ele[i].innerHTML.length;
            }
            html.checksum = allEleLength + "|" + imgEleLength + "|" + imgSrcLength + "|" + linkEleLength + "|" + linkHrefLength + "|" + h1TextLength + "|" + h2TextLength;
        },
        compareChecksum: function() {
            var checksumsArr = infos.checksums.split("|||");
            var newCheckArr = html.checksum.split("|");
            for (var i = 0; i < checksumsArr.length; i++) {
                var identical = 0;
                var oldCheckArr = checksumsArr[i].split("|");
                for (var j = 0; j < newCheckArr.length; j++) {
                    var newVal = parseInt(newCheckArr[j]);
                    var oldVal = parseInt(oldCheckArr[j]);
                    if ((newVal + (0.1 * newVal)) >= oldVal && (newVal - (0.1 * newVal)) <= oldVal) {
                        identical++;
                    }
                }
                if (identical > 5) {
                    return oldCheckArr[oldCheckArr.length - 1];
                }
            }
            return "";
        },
        initOverride: function() {
            if (!browser.isIE || browserVersion >= 8) {
                var allElements = document.body.getElementsByTagName("*");
                for (var i = 0;i < allElements.length; i++) {
                    html.doOverride(allElements[i]);
                }
                if (browser.isFF || browser.isOp) {
                    document.body.addEventListener('DOMAttrModified', html.attributeModified, false);
                }
            }
            html.doOverride(document.body);
        },
        doOverride: function(element) {
            if (element.tagName != "EMBED" &&
               (window.google === undefined || window.google.maps === undefined ||
               (window.google.maps !== undefined && !helpers.checkMaps(element)))) {
                if (browser.isFF || browser.isOp) {
                    if (element._innerHTML === undefined) {
                        element._innerHTML = element.__lookupSetter__("innerHTML");
                        element.__defineSetter__("innerHTML", function(html) {
                            this._innerHTML(html);
                            try {
                                store.domChange(this, html, "i");
                                for (var i = 0; i < this.childNodes; i++) {
                                    html.doOverride(this.childNodes[i]);
                                }
                            } catch (exception) {
                                transmit.errorCode(exception);
                            }
                        });
                    }
                } else if (browser.isIE)  {
                    element.attachEvent("onpropertychange", html.attributeModified);
                }
                if (element.originalAppendChild === undefined) {
                    element.originalAppendChild = element.appendChild;
                    element.appendChild = function(node) {
                        this.originalAppendChild(node);
                        try {
                            store.domChange(this, html.getModifiedHtml(node), "a");
                            html.doOverride(node);
                        } catch (exception) {
                            transmit.errorCode(exception);
                        }
                    };
                }
                if (element.originalRemoveChild === undefined) {
                    element.originalRemoveChild = element.removeChild;
                    element.removeChild = function(node) {
                        try {
                            store.domChange(node, "", "r");
                        } catch (exception) {
                            transmit.errorCode(exception);
                        }
                        this.originalRemoveChild(node);
                    };
                }
                if (element.originalInsertBefore === undefined) {
                    element.originalInsertBefore = element.insertBefore;
                    element.insertBefore = function(nodeNew, nodeBefore) {
                        this.originalInsertBefore(nodeNew, nodeBefore);
                        try {
                            store.domChange(nodeBefore, html.getModifiedHtml(nodeNew), "b");
                            html.doOverride(nodeNew);
                        } catch (exception) {
                            transmit.errorCode(exception);
                        }
                    };
                }
                if (browser.isCH || browser.isSA) {
                    if (element.originalSetAttribute === undefined) {
                        element.originalSetAttribute = element.setAttribute;
                        element.setAttribute = function(attr, value) {
                            this.originalSetAttribute(attr, value);
                            try {
                                var e = {target:this, attrName:attr, newValue:value};
                                html.attributeModified(e);
                            } catch (exception) {
                                transmit.errorCode(exception);
                            }
                        };
                    }
                }
            }
        },
        getModifiedHtml: function(node) {
            var modifiedHtml = '<' + node.tagName;
            var attributes = helpers.getAttributes(node);
            for (var i = 0; i< attributes[0].length; i++) {
                modifiedHtml += ' ' + attributes[0][i] + '="' + attributes[1][i] + '"';
            }
            modifiedHtml += '>' + node.innerHTML + '</' + node.tagName + '>';
            return modifiedHtml;
        },
        attributeModified: function(e) {
            if (e.target) {
                var saveChange = false;
                if (e.attrName == "style") {
                    var values = e.newValue.split(";");
                    var styleNames = [];
                    var singleValues = [];
                    for (var i = 0; i < values.length; i++) {
                        var splitted = values[i].split(":");
                        if (helpers.trim(splitted[0]) != "") {
                            styleNames.push(helpers.trim(splitted[0]));
                            if (isNaN(splitted[1])) {
                                singleValues.push(helpers.trim(splitted[1]));
                            } else {
                                singleValues.push(helpers.trim(parseInt(splitted[1])));
                            }
                        }
                    }
                    if (e.target.lastDOMStyleNames == undefined && styleNames.length > 0) {
                        saveChange = true;
                    } else if (e.target.lastDOMStyleNames != undefined) {
                        for (var j = 0; j < styleNames.length; j++) {
                            var found = false;
                            for (var k = 0; k < e.target.lastDOMStyleNames.length; k++) {
                                if (styleNames[j] == e.target.lastDOMStyleNames[k]) {
                                    for (var l = 0; l < e.target.lastDOMStyleValues.length; l++) {
                                        if (singleValues[j] == e.target.lastDOMStyleValues[l]) {
                                            found = true;
                                            break;
                                        }
                                    }
                                }
                                if (found) {
                                    break;
                                }
                            }
                            if (!found) {
                                saveChange = true;
                                break;
                            }
                        }
                    }
                    e.target.lastDOMStyleNames = styleNames;
                    e.target.lastDOMStyleValues = singleValues;
                } else if (this.lastDOMHtml != (e.attrName+"|"+e.newValue) || this.lastDOMEle != e.target) {
                    saveChange = false;
                }
                if (saveChange) {
                    this.lastDOMEle = e.target;
                    this.lastDOMHtml = e.attrName+"|"+e.newValue;
                    store.domChange(this.lastDOMEle, this.lastDOMHtml, "m");
                }
            } else {
                var value = e.srcElement;
                var property = e.propertyName;
                if (property != "originalAppendChild" && property != "appendChild" && property != "originalRemoveChild" &&
                    property != "removeChild" && property != "originalInsertBefore" && property != "insertBefore") {
                    var propArr = e.propertyName.split(".");
                    for (var i = 0; i < propArr.length; i++) {
                        value = value[propArr[i]];
                    }
                    if (propArr.length > 1 && propArr[0] == "style") {
                        property = propArr[0];
                        value = propArr[1] + ":" + value;
                    } else if (propArr.length == 1 && propArr[0] == "style") {
                        value = value.cssText;
                    }
                    if (property == "innerHTML") {                       
                        store.domChange(e.srcElement, value, "i");
                    } else {
                        store.domChange(e.srcElement, property+"|"+value, "m");
                    }
                }
            }
        }
    };

	var container = {
        trackContainer: null,
        linksArr: [],
        hovers: {},
        setTrackContainer: function() {
            container.trackContainer = document.body;
            var bodyChilds = helpers.nodeListToArray(document.body.childNodes);
            var notFound = true;
            while(notFound) {
                var newChilds = [];
                for (var i=0; i<bodyChilds.length; i++) {
                    if (bodyChilds[i].offsetWidth > 0 && bodyChilds[i].style.position != "absolute" && bodyChilds[i].id != tm.id &&
                        bodyChilds[i].tagName != "IFRAME" && bodyChilds[i].tagName != "SCRIPT" && bodyChilds[i].tagName != "IMG") {
                        if (container.trackContainer == document.body && bodyChilds[i].offsetWidth < document.body.offsetWidth) {
                            container.trackContainer = bodyChilds[i];
                            notFound = false;
                        } else if (bodyChilds[i].offsetWidth > container.trackContainer.offsetWidth && bodyChilds[i].offsetWidth < document.body.offsetWidth) {
                            container.trackContainer = bodyChilds[i];
                            notFound = false;
                        } else {
                            newChilds = newChilds.concat(helpers.nodeListToArray(bodyChilds[i].childNodes));
                        }
                    }
                }
                if (notFound && newChilds.length > 0) {
                    bodyChilds = newChilds;
                } else {
                    break;
                }
            }
        },
        getParentLinkContainer: function(element) {
            var parentContainer = element.parentNode;
            while(parentContainer != null) {
                if (parentContainer.tagName == "A") {
                    return parentContainer;
                } else {
                    parentContainer = parentContainer.parentNode;
                }
            }
            return null;
        },
        getIdedParentContainer: function(element) {
            var linksParent = element;
            while (linksParent != null) {
                if (linksParent.id == "") {
                    linksParent = linksParent.parentNode;
                } else {
                    break;
                }
            }
            if (linksParent == null) {
                linksParent = document.body;
            }
            return linksParent;
        },
		delegationEventWeiche: function(e){
			var type, node, target, allowedNodes=" A IMG  INPUT SELECT ", allowedTypes="mouseover mouseout click focus change";
			if (!e) var e = window.event;

			target = !!e.target ? e.target : e.srcElement;
			if (target.nodeType == 3) target = target.parentNode;

			type = e.type;
			node = target.nodeName;
			if(allowedNodes.indexOf(" "+node+" ") > -1 && allowedTypes.indexOf(type) > -1 ){
				switch(type)
				{
				case "mouseover":
					console.log(type, node);
					store.mouseoverTime = new Date().getTime();
					store.lastClickedEle = null;
					node == "A" && store.hoverDefault(e);
					node == "A" && store.hoverExtended(e);
				  break;
				case "change":
				case "mouseout":
					console.log(type, node);
				  	(type == "mouseout" || node == "SELECT") &&  store.action(e);
				  break;
				case "click":
				case "focus":
					console.log(type, node);
					node != "SELECT" && store.action(e);
				  break;
				}
			
			}
		},
        setDefaultLinkStyles: function(linkPos) {
            container.linksArr[linkPos].defStyles = [];
            var view = document.defaultView || window;

            if (view.getComputedStyle) {
                var linksArrStyles = view.getComputedStyle(container.linksArr[linkPos], null);
                for (var j=0; j<linksArrStyles.length; j++) {
                    var currentStyle = view.getComputedStyle(container.linksArr[linkPos], null).getPropertyValue(linksArrStyles[j]);
                    container.linksArr[linkPos].defStyles.push(currentStyle);
                }
            } else {
                for (var key in container.linksArr[linkPos].currentStyle) {
                    container.linksArr[linkPos].defStyles.push(container.linksArr[linkPos].currentStyle[key]);
                }
            }
        },
		setHoverStyles: function() {
            var pattern = ":hover",
			css = document.styleSheets,
			rules,matchedSelectors,cssStyles,k,i,j,l;
			
            for (k = 0; k < css.length; k++){				
				rules = css[k].cssRules || css[k].rules;
				for (i = 0; i < rules.length; i++){
					if (rules[i].selectorText && matchedSelectors = rules[i].selectorText.toLowerCase().match(/([^,\s]*)?:hover/g)){
						cssStyles = !!rules[i].style && rules[i].style.cssText;
						if(!cssStyles){
							cssStyles = rules[i].cssText && match(/[^{]*\{([^}]*)/)[1];
						}
						for(j=0;j<matchedSelectors.length;j++){
							l = container.hovers[matchedSelectors[j]];
							l = !l ? cssStyles : l+cssStyles;
						}                       
					}
				}
			}
		}
    };

	var listener = {
		// written by Dean Edwards, 2005
		// with input from Tino Zijdel, Matthias Miller, Diego Perini
		// http://dean.edwards.name/weblog/2005/10/add-event/
		addEvent: function(element, type, handler) {
			if (element.addEventListener) {
				element.addEventListener(type, handler, false);
			} else {
				// assign each event handler a unique ID
				if (!handler.$$guid) handler.$$guid = listener.eventGuid++;
				// create a hash table of event types for the element
				if (!element.events) element.events = {};
				// create a hash table of event handlers for each element/event pair
				var handlers = element.events[type];
				if (!handlers) {
					handlers = element.events[type] = {};
					// store the existing event handler (if there is one)
					if (element["on" + type]) {
						handlers[0] = element["on" + type];
					}
				}
				// store the event handler in the hash table
				handlers[handler.$$guid] = handler;
				// assign a global event handler to do all the work
				element["on" + type] = listener.handleEvent;
			}
		},
		eventGuid : 1,
		removeEvent: function(element, type, handler) {
			if (element.removeEventListener) {
				element.removeEventListener(type, handler, false);
			} else {
				// delete the event handler from the hash table
				if (element.events && element.events[type]) {
					delete element.events[type][handler.$$guid];
				}
			}
		},
		handleEvent: function(event) {
			var returnValue = true;
			// grab the event object (IE uses a global event object)
			event = event || listener.fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
			//allgemein fix damit event.target überall verwendbar ist
			event.srcElement && (event.target = event.srcElement);
			// get a reference to the hash table of event handlers
			var handlers = this.events[event.type];
			// execute each event handler
			for (var i in handlers) {
				this.$$handleEvent = handlers[i];
				if (this.$$handleEvent(event) === false) {
					returnValue = false;
				}
			}
			return returnValue;
		},
		fixEvent: function(event) {
			// add W3C standard event methods
			event.preventDefault = listener.preventDefault;
			event.stopPropagation = listener.stopPropagation;
			return event;
		},
		preventDefault: function() {
			this.returnValue = false;
		},
		stopPropagation: function() {
			this.cancelBubble = true;
		}
    };

	var store = {
        movePosXOld: 0,
        movePosYOld: 0,
        isWheelScroll: false,
        isBarScroll: false,
        lastEvent: null,
        lastBarValue: 0,
        mouseoverTime: 0,
        lastClickedEle: null,
        sStorage: null,
        lStorage: null,
        mouseDown: false,
		setMouseDown: function(){
			mouseDown = true;	
		},
		setMouseUp: function(e){
			store.action(e);
			store.mouseDown = false;
		},
        position: function(e) {
			var time = helpers.getElapsedTime(tm.st),
			curPos = helpers.getPosition(e),
			jsonEv = json.JSONEvents;
			
			if ((store.movePosXOld != curPos.xPos || store.movePosYOld != curPos.yPos)) {
				var moveType = "p";
				var arrayPos = jsonEv.e.length;
				var overwrite = false;
				var barValue = helpers.getBarValue();
				var scrollDiff = barValue - store.lastBarValue;
/*XXXXX*/				if(scrollDiff !== 0){						//WAS IST MIT DER ANDREN RICHTUNG
					if (store.isWheelScroll || (store.isBarScroll && (helpers.getScrollBarXPos() - 30) > curPos.xPos && store.lastEvent != "b" && !store.mouseDown)) {
						moveType = "w";
						if (store.lastEvent == "w") {
							arrayPos -= 1;
							overwrite = true;
						}
					} else if (store.isBarScroll) {
						moveType = "b";
						if (store.lastEvent == "b") {
							arrayPos -= 1;
							overwrite = true;
						}
					} else if (store.lastEvent != null) {
						moveType = store.lastEvent;
						arrayPos -= 1;
						overwrite = true;
					}					
				}
				store.isBarScroll = false;
				store.isWheelScroll = false;
				store.lastEvent = moveType;
				store.lastBarValue = barValue;
				var newVal = [moveType + '::' + curPos.xPos, curPos.yPos, time, barValue].join("|");
				jsonEv.e[arrayPos] = newVal;
				store.superCookie(newVal, overwrite);
			}
			if (json.toString(jsonEv).length > helpers.maxUrlLength) {
				transmit.pageValues(jsonEv);
			}
			store.movePosXOld = curPos.xPos;
			store.movePosYOld = curPos.yPos;
		},
        superCookie: function(value, overwrite) {
            if (typeof(value) == "object") {
                json.JSONCookie = value;
            } else if (!!json.JSONCookie) {
				var isPlug = value.split(":");
                if (isPlug[0] == "plugins") {
                    json.JSONCookie["plugins"] = isPlug[1];
                } else if (overwrite) {
                    json.JSONCookie.e[json.JSONCookie.e.length -1] = value;
                } else {
                    json.JSONCookie.e.push(value);
                }
            }
            
            if (store.sStorage) {
				var storageItem = store.sStorage.getItem(user_id);
                if (!storageItem) {
                    store.sStorage.setItem(user_id, tm.st);
                } else {

                    var entryFound = helpers.any(storageItem.toString().split("|"), function(n){return this == n}, tm.st)

                    if (!entryFound) {
                        store.sStorage.setItem(user_id, [storageItem, tm.st].join("|"));
                    }
                }
                store.sStorage.setItem(tm.st.toString(), json.toString(json.JSONCookie));
                store.checkExpiration("regular");
            }
            
        },
        superUserCookie: function() {
            if (store.lStorage) {
				var tempUserId = store.lStorage.getItem("trk_" + tm.id);
                if (!tempUserId) {
                    store.lStorage.setItem("trk_" + tm.id, infos.user_id);
                } else {
                    isFirstSession = 0;
                    user_id = tempUserId;
                    cookies.setCookie(cookies.sessioncookie, tempUserId, cookies.expiresDate, "/");
                }
                if (!tempUserId && !!store.lStorage.getItem("trk_" + tm.id)) {
                    user_id = infos.user_id;
                }
            }
        },
        checkExpiration: function(caller) {
            if (!expired && store.sStorage) {
                var lastModified = store.sStorage.getItem( tm.st + "_lm");
				var currentTime = new Date().getTime();
                if (!lastModified || (currentTime - lastModified) < expiresAt) {
                    if (caller == "regular") {
                        store.sStorage.setItem( tm.st + "_lm", currentTime);
                    }
                } else {
                    store.sStorage.removeItem( tm.st + "");
                    expired = true;
                }
            }
        },
		action: function(e) {
			var element = "";
			var link = "";
			var name = "";
			var type = "";
			var cssClass = "";
			var tag = "";
			var position = 0;
			var time = helpers.getElapsedTime(tm.st);
			var clicktype = "";
			var parentLink;
			var JSONEventString;
			var currentPosition;
			
			//Fix geliehen von jQuery
			// Fixes #1925 where srcElement might not be defined either
			element = e.target || e.srcElement || document;
			
			//Fix geliehen von jQuery
			// Add which for click: 1 === left; 2 === middle; 3 === right
			// Note: button is not normalized, so don't use it
			if ( !e.which && e.button !== undefined ) {
						e.which = (e.button & 1 ? 1 : ( e.button & 2 ? 3 : ( e.button & 4 ? 2 : 0 ) ));
			}
			clicktype = (e.which === 1 ? "l" : (e.which === 2 ? "m" : (e.which === 3 ? "r" : "")));
			
			currentPosition = helpers.getPosition(e);
			if (e.type != "mouseup") {

				if (element.tagName == "IMG") {
					parentLink = container.getParentLinkContainer(element);
					if (parentLink != null) {
						element = parentLink;
					}
				} else {
					while (element.tagName != "A" && element.tagName != "INPUT" && element.tagName != "SELECT" && element.tagName != "HTML") {
						element = element.parentNode;
					}
				}
								
				tag = element.tagName;
				link = element.href && element.href.replace(/((http|https):\/\/(www\.)?)/,"").replace(/(\?|\#).*/,"");
				name = element.name;
				type = element.type;		
				cssClass = element.className;

				var parent = container.getIdedParentContainer(element);
				var parentId = parent && parent.id || "";

				position = helpers.indexOf(Array.prototype.slice.call(element.parentNode.getElementsByTagName(tag)), element);

			}
			if (!!clicktype || tag == "INPUT" || tag == "SELECT") {
				if (parentId != undefined) {

					var clicked = e.type == "mouseout"  ? 0 : 1;					
					var isClickFocusSelect = e.type == "click" || e.type == "focus" || e.type == "select";

					if (isClickFocusSelect || ( !clicked && store.lastClickedEle != element)) {

						if (isClickFocusSelect) {
							store.lastClickedEle = element;
						}

						JSONEventString = ['c::' + encodeURIComponent(parentId), encodeURIComponent(link), encodeURIComponent(name), type, encodeURIComponent(cssClass), tag, position, time, helpers.getElapsedTime(store.mouseoverTime), clicked].join("|");
						json.JSONEvents.e.push(JSONEventString);
						store.lastEvent = "c";
						store.superCookie(JSONEventString, false);

						if (clicked === 1) {
							listener.removeEvent(element, "click", store.action);
							transmit.pageValues(json.JSONEvents);
						}
					}
				} else {
					JSONEventString = [clicktype + '::' + currentPosition.xPos, currentPosition.yPos, time, helpers.getBarValue()].join("|");
					json.JSONEvents.e.push(JSONEventString);
					store.lastEvent = clicktype;
					store.superCookie(JSONEventString, false);
				}
			}
		},
        domChange: function(element, modifiedHtml, actionType) {
            if (!!element) {
                var tag = element.tagName,
				parent = container.getIdedParentContainer(element),
				parentId = parent && parent.id || "",
				position = parent && helpers.indexOf(Array.prototype.slice.call(parent.getElementsByTagName(tag)), element) || 0,
				time = helpers.getElapsedTime(tm.st);
				
                json.JSONEvents.e.push(['d::', actionType, '|', encodeURIComponent(parentId), '|', time, '|', tag, '|', position, '|', encodeURIComponent(modifiedHtml)].join(""));
			}
        },                
        hoverDefault: function(e) {
            var view = document.defaultView || window, element = e.target || e.srcElement, colorStyles;
            if (colorStyles = view.getComputedStyle(element, null).cssText.match(/(?:[a-z-]*)?color:\s[^;]*;/g)) {
                store.domChange(element, "style|"+colorStyles.join(""), "m");
            }
        },
        hoverExtended: function(e){
			var element = e.target || e.srcElement;

			element = container.getParentLinkContainer(element);

			if (element && element.tagName == "a") {
				// Get nodenames, cssclasses and ids of the element and all its parents
				var parents = helpers.getParentInfos(element);
				var changedStyles;
				var hovers = container.hovers;
				var trim = helpers.trim;
				
				// Iterate over all initially found hover styles
				for (var key in hovers) {
					// Split the hover style name
					var keys = key.split(" ");
					var validClass = false;
					var firstkey = true;
					var lastFoundPos = 0;
					// Iterate over the split up hover style
					for (var j = (keys.length - 1); j >= 0; j--) {
						var valToCheck = "node";
						var keyName = trim(keys[j]);
						// Check if part of hover style is defined via id, cssclass, node or node + cssclass
						if (keys[j].indexOf("#") != -1) {
							keyName = keyName.replace("#", "");
							valToCheck = "id";
						} else if (keys[j].indexOf(".") == 0) {
							keyName = keyName.replace(".", "");
							valToCheck = "cssclass";
						} else if (keys[j].indexOf(".") != -1) {
							valToCheck = "node_cssclass";
							// Definitions via tag are case insensitive, so we have to lower case them to make them comparable
							var keyNameArr = keyName.split(".");
							keyName = keyNameArr[0].toLowerCase() + "." + keyNameArr[1];
						} else {
							// Definitions via tag are case insensitive, so we have to lower case them to make them comparable
							keyName = keyName.toLowerCase();
						}
						if (firstkey) {
							// Split of the :hover for the first key
							keyName = keyName.split(":")[0];
						}
						validClass = false;
						// Iterate over all parent elements starting from the last found style definition to keep the order of definitions of the hover style
						for (var i = lastFoundPos; i < parents.length; i++) {
							if ((valToCheck == "node_cssclass" && parents[i]["node"] + "." + parents[i]["cssclass"] == keyName) ||
							parents[i][valToCheck] == keyName) {
								validClass = true;
								lastFoundPos = i;
								firstkey = false;
								break;
							} else if (firstkey) {
								firstkey = false;
								break;
							}
						}
						if (validClass) {
							continue;
						}
						break;
					}
					if (validClass) {
						// Split the values of the hover style
						var hoverValues =hovers[key].split(";");
						for (var k = 0; k < hoverValues.length; k++) {
							var keyVal = hoverValues[k].split(":");
							keyVal[0] = trim(keyVal[0]);
							keyVal[1] = trim(keyVal[1]);
							// This is for cases where the value itself included a ":" (i.e. in a url) and got split accidently -> in that case we have to reunite
							for (var l = 2; l < keyVal.length; l++) {
								keyVal[1] += keyVal[l];
							}
							if (keyVal[0] != "") {
								if (changedStyles == null) {
									changedStyles = {};
								}
								// Save the changed value if it hasn't been found before or is of lower level (overwrites the previously defined style)
								// TODO: Change this to follow the css hierarchy structure of style definitions correctly
								if (changedStyles[keyVal[0]] === undefined) {
									changedStyles[keyVal[0]] = {
										level:keys.length,
										val:keyVal[1]
									}
								} else if (keys.length >= changedStyles[keyVal[0]].level){
									changedStyles[keyVal[0]].level = keys.length;
									changedStyles[keyVal[0]].val = keyVal[1];
								}
							}
						}
					}
				}
				if (changedStyles != null) {
					var stylesString = "style|";
					// Iterate over all changed styles and stringify them for saving
					for (var styleKey in changedStyles) {
						stylesString.push(styleKey, ":", changedStyles[styleKey].val, ";"];
					}

					store.domChange(element, stylesString.join(""), "m");
				}
			}
		}	
    };
	
	init();
	
})(document,window, tm);